package com.baiwei.vpnapi.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baiwei.vpnapi.dao.*;
import com.baiwei.vpnapi.entity.*;
import com.baiwei.vpnapi.entity.reqentity.PaymentInput;
import com.baiwei.vpnapi.entity.respentity.AvailablePackage;
import com.baiwei.vpnapi.entity.respentity.DiscountPackage;
import com.baiwei.vpnapi.exception.AccountException;
import com.baiwei.vpnapi.exception.BusinessEnum;
import com.baiwei.vpnapi.exception.PaymentException;
import com.baiwei.vpnapi.exception.VpnException;
import com.baiwei.vpnapi.service.PayService;
import com.baiwei.vpnapi.utils.AppUtils;
import com.baiwei.vpnapi.utils.ApplePayUtils;
import com.baiwei.vpnapi.utils.JwtTokenUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sun.org.apache.xpath.internal.operations.Mod;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @program: vpnapi
 * @description: 支付服务实现
 * @author: Mr. Stone
 * @create: 2020-03-07 10:41
 **/

@Service(value = "paymentService")
public class PayServiceImpl implements PayService {
    @Autowired
    private HttpServletRequest request;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private VpnPackageMapper vpnPackageMapper;

    @Autowired
    private PackageOrderMapper packageOrderMapper;

    @Autowired
    private UserPackageMapper userPackageMapper;

    @Autowired
    private PaymethodMapper paymethodMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private Logger logger = LoggerFactory.getLogger(PayServiceImpl.class);

    @Value("${paydollar.payurl}")
    private String payUrl;

    @Value("${paydollar.merchant}")
    private String merchant;

    @Value("${paydollar.token}")
    private String payToken;

    @Value("${paydollar.curCode}")
    private String curCode;

    @Value("${paydollar.cancelUrl}")
    private String cancelUrl;

    @Value("${paydollar.successUrl}")
    private String successUrl;

    @Value("${paydollar.failUrl}")
    private String failUrl;

    @Value("${iosconf.iospayurl}")
    private String iosValidUrl;


//    @Transactional
//    public String mpaySuccessCharage() {
//        String orderNo = request.getParameter("ordernum");
//        String payResultCode = request.getParameter("rspcode");
//        logger.info("\nmpay success callback\n");
//        logger.info("orderNo: {}\nresultCode:{}", orderNo, payResultCode);
//        PackageOrder qorder = new PackageOrder();
//        qorder.setOrderNo(orderNo);
//        PackageOrder rorder = packageOrderMapper.selectOne(new QueryWrapper<>(qorder));
//        if (rorder == null) {
//            logger.info("order {} not exist.", orderNo);
//            throw new RuntimeException("order not exist");
//        }
//        if(rorder.getStatus().equals(1)) {
//            return "ok";
//        }
//        if (payResultCode.equals("100")) {
//            logger.info("order {} pay success", orderNo);
//            rorder.setStatus(1);
//            Integer packageId = rorder.getPackageId();
//            Integer userId = rorder.getUserId();
//            dispatchPackage(userId, packageId, orderNo);
//        } else {
//            logger.info("order {} pay failed", orderNo);
//            rorder.setStatus(2);
//        }
//        rorder.setCompleteTime(new Date());
//        logger.info("order {} update", rorder);
//        packageOrderMapper.updateById(rorder);
//        return "ok";
//    }

    @Transactional
    public String successCharge() {
        String orderNo = request.getParameter("Ref");
        String payResultCode = request.getParameter("successcode");
        logger.info("\npaydollar success callback\n");
        logger.info("orderNo: {}\nresultCode:{}", orderNo, payResultCode);
        PackageOrder qorder = new PackageOrder();
        qorder.setOrderNo(orderNo);
        PackageOrder rorder = packageOrderMapper.selectOne(new QueryWrapper<>(qorder));
        if (rorder == null) {
            logger.info("order {} not exist.", orderNo);
            throw new RuntimeException("order not exist");
        }
        if(rorder.getStatus().equals(1)) {
            return "ok";
        }
        if (payResultCode.equals("0")) {
            logger.info("order {} pay success", orderNo);
            rorder.setStatus(1);
            Integer packageId = rorder.getPackageId();
            Integer userId = rorder.getUserId();
            dispatchPackage(userId, packageId, orderNo);
        } else {
            logger.info("order {} pay failed", orderNo);
            rorder.setStatus(2);
        }
        rorder.setCompleteTime(new Date());
        logger.info("order {} update", rorder);
        packageOrderMapper.updateById(rorder);
        return "ok";
    }

    /**
     * @Description: 下发套餐
     * @Param: @userid @packageId
     * @return:
     * @Author: Mr.Stone
     * @Date: 2020/3/14
     */
    @Transactional
    public void dispatchPackage(Integer userId, Integer packageId, String orderNo) {
        logger.info("dispatch package:{}\nto user:{}\norderNo:{}", packageId, userId, orderNo);
        UserPackage qup = new UserPackage();
        qup.setUserId(userId);
        qup.setOrderNo(orderNo);

        AvailablePackage tup = userPackageMapper.findLastUnusedOrInusePackage(userId);
        logger.info("user:{} lasted package: {}", userId, tup);
        VpnPackage qp = new VpnPackage();
        qp.setPackageId(packageId);
        VpnPackage pack = vpnPackageMapper.selectOne(new QueryWrapper<>(qp));
        logger.info("dispatch package info: {}", pack);
        if (tup == null) {
            logger.info("user has no current valid package");
            //没有在使用的套餐
            long dalta = pack.getDuration().longValue() * 3600 * 24 * 1000;
            long nowsamp = System.currentTimeMillis();
            long endsamp = System.currentTimeMillis() + dalta;
            Date startDate = new Date(nowsamp);
            Date endDate = new Date(endsamp);
            qup.setStartTime(startDate);
            qup.setEndTime(endDate);
            qup.setStatus(1);
            qup.setPackageId(new Integer(packageId));
            logger.info("insert user_package {}", qup);
        } else {
            logger.info("user has valid package: {}", tup);
            long dalta = pack.getDuration().longValue() * 3600 * 24 * 1000;
            long nowsamp = tup.getEndTime().getTime();
            long endsamp = nowsamp + dalta;
            qup.setStatus(2);
            qup.setStartTime(new Date(nowsamp));
            qup.setEndTime(new Date(endsamp));
            qup.setPackageId(new Integer(packageId));
            logger.info("insert user_package {}", qup);
        }
        userPackageMapper.insert(qup);
    }

//    public String commitMpayOrder(PaymentInput input, Model model) {
//        logger.info("commit order info: {}", input);
//        input.validation();
//
//        String token = request.getHeader("Authorization");
//        String userIdString = jwtTokenUtil.getUsernameFromToken(token);
//        Integer payMethodId = new Integer(input.getPayMethod());
//        VpnPaymethod qpm = new VpnPaymethod();
//        qpm.setItemId(payMethodId);
//        VpnPaymethod paymethod = paymethodMapper.selectOne(new QueryWrapper<>(qpm));
//        if (paymethod == null) {
//            throw new RuntimeException("支付方式不存在");
//        }
//        logger.info("paymethod is {}.", paymethod);
//        String packageId = input.getPackageId();
//        VpnPackage pack = vpnPackageMapper.selectById(packageId);
//        if (pack == null) {
//            throw new PaymentException(BusinessEnum.PAYMENT_PACKAGE_NOT_EXIST);
//        }
//
//
//        Map<String, Object> info = new TreeMap<>();
//        info.put("paymethod", paymethod.getMpayId());
//        info.put("salt", AppUtils.genSalt());
//        info.put("securekey", "E9750E947CE0DC98");
//        info.put("accounttype", "V");
//        info.put("amt", pack.getActualPrice().toString());
//        info.put("currency", "HKD");
//        info.put("customerid", "12579841156496431634");
//        info.put("datetime", AppUtils.nowTimeString());
//        info.put("locale", "zh_TW");
//        info.put("merchant_tid", "001");
//        info.put("merchantid", "1100460");
//        info.put("notifyurl", "https://api.ponyspeeduptest.com/pay/mpaysuccess");
//        info.put("returnurl", "https://api.ponyspeeduptest.com/CallBack/payReceiveNotice");
//        String orderNo = AppUtils.generateOrder();
//        info.put("ordernum", orderNo);
//        info.put("securekey", "E9750E947CE0DC98");
//        model.addAllAttributes(info);
//        String hash = AppUtils.genInfoString(info);
//        model.addAttribute("hash", hash);
//        model.addAttribute("payurl", "https://demo.mobiletech.com.hk/MPay/MerchantPay.jsp");
//
//        //插入订单
//        PackageOrder order = new PackageOrder();
//        order.setPackageId(new Integer(packageId));
//        // 0 待支付 1 支付成功 2 支付失败
//        order.setStatus(0);
//        order.setMoney(pack.getActualPrice());
//        order.setMoneyUnit(pack.getActualPriceUnit().toString());
//        order.setUserId(new Integer(userIdString));
//        order.setOrderNo(orderNo);
//        order.setCreateTime(new Date());
//        order.setPaymentId(paymethod.getPaymentId());
//        order.setPaymentType(paymethod.getItemId());
//        String ipAddr = AppUtils.getIpAddr(request);
//        order.setIpAddr(ipAddr);
//        packageOrderMapper.insert(order);
//        logger.info("insert order {}", order);
//        return "mpay";
//    }

    public String commitOrder(PaymentInput input, Model model) {
        logger.info("commit order info: {}", input);
        input.validation();

        String token = request.getHeader("Authorization");
        String userIdString = jwtTokenUtil.getUsernameFromToken(token);
        Integer payMethodId = new Integer(input.getPayMethod());
        VpnPaymethod qpm = new VpnPaymethod();
        qpm.setItemId(payMethodId);
        VpnPaymethod paymethod = paymethodMapper.selectOne(new QueryWrapper<>(qpm));
        if (paymethod == null) {
            throw new RuntimeException("支付方式不存在");
        }
        logger.info("paymethod is {}.", paymethod);
        model.addAttribute("payMethod", paymethod.getEnglishName());
        String packageId = input.getPackageId();
        DiscountPackage pack = vpnPackageMapper.getDiscountPackageById(Integer.valueOf(packageId));

        if (pack == null) {
            throw new PaymentException(BusinessEnum.PAYMENT_PACKAGE_NOT_EXIST);
        }
        String orderNo = AppUtils.generateOrder();
        String price = pack.getActualPrice().toString();
        // 有有效的优惠走优惠价格
        Date now = new Date();
        if(pack.getDiscountStartTime() != null &&
                pack.getDiscountEndTime() != null &&
                pack.getDiscountStartTime().compareTo(now) < 0 &&
                pack.getDiscountEndTime().compareTo(now) > 0) {
            price = pack.getDiscountHkPrice().toString();
        }
        String payType = "N";
        String sha1TokenSource = String.format("%s|%s|%s|%s|%s|%s", merchant, orderNo, curCode, price, payType, payToken);
        String sha1Token = DigestUtils.sha1Hex(sha1TokenSource);
        String ipAddr = AppUtils.getIpAddr(request);
        model.addAttribute("successUrl", successUrl);
        model.addAttribute("cancelUrl", cancelUrl);
        model.addAttribute("failUrl", failUrl);
        model.addAttribute("merchantId", merchant);
        model.addAttribute("orderRef", orderNo);
        model.addAttribute("currCode", curCode);
        model.addAttribute("amount", price);
        model.addAttribute("payType", payType);
        model.addAttribute("secureHash", sha1Token);
        model.addAttribute("payurl", payUrl);
        logger.info("form data : {}", model);
        //插入订单
        PackageOrder order = new PackageOrder();
        order.setPackageId(new Integer(packageId));
        // 0 待支付 1 支付成功 2 支付失败
        order.setStatus(0);
        order.setMoney(Double.valueOf(price));
        order.setMoneyUnit(pack.getActualPriceUnit().toString());
        order.setUserId(new Integer(userIdString));
        order.setOrderNo(orderNo);
        order.setCreateTime(new Date());
        order.setPaymentId(paymethod.getPaymentId());
        order.setPaymentType(paymethod.getItemId());
        order.setIpAddr(ipAddr);
        packageOrderMapper.insert(order);
        logger.info("insert order {}", order);
        return "test";
    }

    private HashMap<String, String> appleProductMap() {
        HashMap<String, String> res = new HashMap<>();
        res.put("com.ponytech.vpn.macos.basic7days", "com.ponytech.vpn.iphone.basic7days");
        res.put("com.ponytech.vpn.macos.basic1month", "com.ponytech.vpn.iphone.basic1month");
        res.put("com.ponytech.vpn.macos.basic3month", "com.ponytech.vpn.iphone.basic3month");
        res.put("com.ponytech.vpn.macos.basic6month", "com.ponytech.vpn.iphone.basic6month");
        res.put("com.ponytech.vpn.macos.basic12month", "com.ponytech.vpn.iphone.basic12month");
        return res;
    }

    public String iosPay(String transactionId, String payload) {
        String plat = request.getHeader("platform");
        boolean isMac = plat.equals("4");
        String token = request.getHeader("Authorization");
        String userIdString = jwtTokenUtil.getUsernameFromToken(token);
        logger.info("user {} ios validation\ntransactionId:{}\npayload:{}", userIdString, transactionId, payload);
        logger.info("iosValidUrl: {}", iosValidUrl);
        String verifyResult = ApplePayUtils.buyAppVerify(payload, 1);
        logger.info("validation result: {}", verifyResult);
        if (verifyResult == null) {
            throw new RuntimeException("苹果验证失败，返回数据为空");
        } else {
            JSONObject appleReturn = JSONObject.parseObject(verifyResult);
            String states = appleReturn.getString("status");
            //无数据则沙箱环境验证
            if ("21007".equals(states)) {
                verifyResult = ApplePayUtils.buyAppVerify(payload, 0);
                appleReturn = JSONObject.parseObject(verifyResult);
                states = appleReturn.getString("status");
            } else {
                throw new RuntimeException("苹果验证失败，返回数据为空");
            }
            // 前端所提供的收据是有效的    验证成功
            if (states.equals("0")) {
                String receipt = appleReturn.getString("receipt");
                JSONObject returnJson = JSONObject.parseObject(receipt);
                String inApp = returnJson.getString("in_app");
                List<HashMap> inApps = JSONObject.parseArray(inApp, HashMap.class);
                if (!CollectionUtils.isEmpty(inApps)) {
                    HashMap<String, String> tran = new HashMap<>();
                    boolean isOk = false;
                    for (HashMap<String, String> app : inApps) {
                        String tranId = app.get("transaction_id");
                        if (tranId != null && tranId.equals(transactionId)) {
                            isOk = true;
                            tran = app;
                        }
                    }
                    //交易列表包含当前交易，则认为交易成功
                    if (isOk) {
                        if (isMac) {
                            VpnPackage qp = new VpnPackage();
                            HashMap<String, String> proMap = appleProductMap();
                            String real_pro_id = proMap.get(tran.get("product_id"));
                            logger.info("current tran is:\n {}\nproduct_map is\n {}\nreal_pro_id is {}", tran, proMap,real_pro_id);
                            qp.setAppleProductId(real_pro_id);
                            VpnPackage rp = vpnPackageMapper.selectOne(new QueryWrapper<>(qp));
                            if (rp == null) {
                                throw new PaymentException(BusinessEnum.PAYMENT_PACKAGE_NOT_EXIST);
                            }
                            String orderNo = insertIosOrder(new Integer(userIdString), rp, true);
                            dispatchPackage(new Integer(userIdString), rp.getPackageId(), orderNo);
                            return "交易成功";
                        }
                        VpnPackage qp = new VpnPackage();
                        qp.setAppleProductId(tran.get("product_id"));
                        VpnPackage rp = vpnPackageMapper.selectOne(new QueryWrapper<>(qp));
                        if (rp == null) {
                            throw new PaymentException(BusinessEnum.PAYMENT_PACKAGE_NOT_EXIST);
                        }
                        String orderNo = insertIosOrder(new Integer(userIdString), rp, true);
                        dispatchPackage(new Integer(userIdString), rp.getPackageId(), orderNo);
                        return "交易成功";
                    }

                    throw new RuntimeException("当前交易不在交易列表中");
                }
                throw new RuntimeException("未能获取获取到交易列表");
            } else {
                throw new RuntimeException("支付失败，错误码：" + states);
            }
        }
    }

    public String insertIosOrder(Integer userId, VpnPackage pack, Boolean result) {
        PackageOrder order = new PackageOrder();
        order.setPackageId(pack.getPackageId());
        // 0 待支付 1 支付成功 2 支付失败
        if (result) {
            order.setStatus(1);
        } else {
            order.setStatus(0);
        }
        order.setMoney(pack.getActualPrice());
        order.setMoneyUnit(pack.getActualPriceUnit().toString());
        order.setUserId(userId);
        String orderNo = AppUtils.generateOrder();
        order.setOrderNo(orderNo);
        order.setCreateTime(new Date());
        order.setCompleteTime(new Date());
        order.setPaymentId(6);
        order.setPaymentType(7);
        order.setIpAddr(AppUtils.getIpAddr(request));
        packageOrderMapper.insert(order);
        logger.info("insert order of ios pay {}", order);
        return orderNo;
    }

    /**
     * web订单提交 (已废弃)
     * */
    public String commitOrderForWeb(String payMethod, String packageId, String token, Model model) {
        logger.info("commit order info payMethod: {}, packageId: {}", payMethod, packageId);
        String userIdString = jwtTokenUtil.getUsernameFromToken(token);
        Integer payMethodId = new Integer(payMethod);
        VpnPaymethod qpm = new VpnPaymethod();
        qpm.setItemId(payMethodId);
        VpnPaymethod paymethod = paymethodMapper.selectOne(new QueryWrapper<>(qpm));
        if (paymethod == null) {
            throw new RuntimeException("支付方式不存在");
        }
        logger.info("paymethod is {}.", paymethod);
        model.addAttribute("payMethod", paymethod.getEnglishName());
        VpnPackage pack = vpnPackageMapper.selectById(packageId);
        if (pack == null) {
            throw new PaymentException(BusinessEnum.PAYMENT_PACKAGE_NOT_EXIST);
        }

        String orderNo = AppUtils.generateOrder();
        String price = pack.getActualPrice().toString();
        String payType = "N";
        String sha1TokenSource = String.format("%s|%s|%s|%s|%s|%s", merchant, orderNo, curCode, price, payType, payToken);
        String sha1Token = DigestUtils.sha1Hex(sha1TokenSource);
        model.addAttribute("successUrl", successUrl);
        model.addAttribute("cancelUrl", cancelUrl);
        model.addAttribute("failUrl", failUrl);
        model.addAttribute("merchantId", merchant);
        model.addAttribute("orderRef", orderNo);
        model.addAttribute("currCode", curCode);
        model.addAttribute("amount", price);
        model.addAttribute("payType", payType);
        model.addAttribute("secureHash", sha1Token);
        model.addAttribute("payurl", payUrl);
        logger.info("form data : {}", model);
        //插入订单
        PackageOrder order = new PackageOrder();
        order.setPackageId(new Integer(packageId));
        // 0 待支付 1 支付成功 2 支付失败
        order.setStatus(0);
        order.setMoney(pack.getActualPrice());
        order.setMoneyUnit(pack.getActualPriceUnit().toString());
        order.setUserId(new Integer(userIdString));
        order.setOrderNo(orderNo);
        order.setCreateTime(new Date());
        order.setPaymentId(paymethod.getPaymentId());
        order.setPaymentType(paymethod.getItemId());
        packageOrderMapper.insert(order);
        logger.info("insert order {}", order);
        return "test";
    }

    // 手动添加套餐
    public String vipBuy(String packageId, String username) {
        VpnUser qUser = new VpnUser();
        qUser.setUsername(username);
        VpnUser cUser = userMapper.selectOne(new QueryWrapper<>(qUser));
        if (cUser == null) {
            throw new AccountException(BusinessEnum.USER_LOGIN_NOT_EXIST);
        }
        VpnPackage qPack = new VpnPackage();
        qPack.setPackageId(new Integer(packageId));
        VpnPackage rPack = vpnPackageMapper.selectOne(new QueryWrapper<>(qPack));
        if (rPack == null) {
            throw new PaymentException(BusinessEnum.PAYMENT_PACKAGE_NOT_EXIST);
        }
        PackageOrder order = new PackageOrder();
        order.setPackageId(new Integer(packageId));
        // 0 待支付 1 支付成功 2 支付失败
        order.setStatus(1);
        order.setMoney(rPack.getActualPrice());
        order.setMoneyUnit(rPack.getActualPriceUnit().toString());
        order.setUserId(cUser.getUserId());
        String orderNo = AppUtils.generateOrder();
        order.setOrderNo(orderNo);
        order.setCreateTime(new Date());
        order.setCompleteTime(new Date());
        order.setPaymentId(8);
        order.setPaymentType(11);
        packageOrderMapper.insert(order);

        dispatchPackage(cUser.getUserId(), new Integer(packageId), orderNo);
        stringRedisTemplate.opsForValue().set("adminToken", AppUtils.generateAuthCode());
        return "success";
    }

}
